/*
---- 
This file is part of SECONDO.

Copyright (C) 2004, University in Hagen, Department of Computer Science, 
Database Systems for New Applications.

SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
----

May, 2007 Leonardo Azevedo, Rafael Brand

Mar, 2010 Leonardo Azevedo, Leo Antunes

*/
//---------------------------------------------------------------------------

#define CONFIDENCE_INTERVAL 1.96 //95%
#define VARIANCE 0.020833
#define VARIANCE_PxP 0.0030382
#define VARIANCE_PxM 0.013454
#define VARIANCE_PxC 0.020833
#define VARIANCE_MxM 0.023872


#include "Signature4CRS.h"
#include <math.h>

long sameScales = 0, differentScales = 0;

#define larger(a,b) ((a>b) ? a : b)
#define smaller(a,b) ((a<b) ? a : b)

Signature4CRS::Signature4CRS( unsigned long id, MBR mbr, unsigned dx,
                                unsigned dy, unsigned potency, void* buffer,
                                long bufSize ) :
//map( &(attr_map.header) ),
sizeOfBlock( 0x1lu << potency  ),
attr_map( id,mbr,dx,dy,potency )
{
  memcpy( attr_map.bits0, buffer, bufSize );
  map = new RasterMap4CRS::Header( id, mbr, dx, dy, potency ) ;
}

Signature4CRS::Signature4CRS( unsigned long id,  Coordinate min, Coordinate max,
                        unsigned long sizeOfBlock, unsigned dx,
                        unsigned dy, const Weight weight[] ) :
//map( &(attr_map.header) ),
sizeOfBlock( sizeOfBlock )
{
  //cout << "Signature4CRS::Signature4CRS 2" << endl;
  MBR mbr;
  mbr.min = min;
  mbr.max = max;
  unsigned potency = 0x1lu >> sizeOfBlock;
  map = new RasterMap4CRS::Header( id, mbr, dx, dy, potency ) ;
  register unsigned i, j, step;
  Weight current;
  GroupOfBits bits0 = 0, bits1 = 0;

  attr_map.header.id = id;
  attr_map.header.mbr.min = min;
  attr_map.header.mbr.max = max;
  attr_map.header.dx = dx;
  attr_map.header.dy = dy;

  for( i = 0; (sizeOfBlock >> i) != 0; i++ );
    attr_map.header.potency = i - 1;
  
  map->potency = attr_map.header.potency;
  
  for( i = 0; i < MAX_BITS; i++ )
  {
    attr_map.bits0[ i ] = attr_map.bits1[ i ] = 0;
  }

  for( step = 8 * sizeof( unsigned long ), i = j = 0; i < dx * dy; i++ )
  {
    step--;

    current = weight[ i ];
    bits0 |= ((current & 0x1lu) >> 0) << step;
    bits1 |= ((current & 0x2lu) >> 1) << step;

    if( step == 0 )
    {
      attr_map.bits0[ j ] = bits0;
      attr_map.bits1[ j ] = bits1;
      j++;
      step = 8 * sizeof( GroupOfBits );

      bits0 = bits1 = 0;
    }
  }

  if( step != 0 && j < MAX_BITS )
  {
    attr_map.bits0[ j ] = bits0;
    attr_map.bits1[ j ] = bits1;
  }
}

void Signature4CRS::RasterMap4CRS::setGroupOfBits(Weight o)
{
  memset(bits0,o,MAX_BITS*sizeof(GroupOfBits));
  memset(bits1,o,MAX_BITS*sizeof(GroupOfBits));
}

Signature4CRS::Weight Signature4CRS::RasterMap4CRS::block( int x, int y ) const
{
  if((x > -1 && y > -1) && ((unsigned)x < header.dx && (unsigned)y < header.dy))
  {
    unsigned index = x*header.dy + y,
             position = index / (8 * sizeof( GroupOfBits )),
             displacement = 8 * sizeof( GroupOfBits ) - 1 
             - (index % (8 * sizeof( GroupOfBits )));

	return (Weight) ((bits0[ position ] & (0x1lu << displacement) ? 0x1 : 0x0) |
                     (bits1[ position ] & (0x1lu << displacement) ? 0x2 : 0x0));

  }
  else {
    return Empty;
  }
}

Signature4CRS::Weight Signature4CRS::block( Coordinate min, 
           unsigned long sizeOfBlock ) const
{
  return block( min.x, min.y, sizeOfBlock );
}

Signature4CRS::Weight Signature4CRS::resolutionChange(int x, int y,
                        unsigned long sizeOfBlock) const
{
  double totalWeight = 0;
  int factor = (unsigned) (sizeOfBlock/this->sizeOfBlock),
          startX = x < 0 ? 0 : x,
          startY = y < 0 ? 0 : y,
          endX = x + factor > (int) map->dx ? map->dx : x + factor,
          endY = y + factor > (int) map->dy ? map->dy : y + factor,
          i, j;

  for( i = startX; i < endX; i++ )
    for( j = startY; j < endY; j++ )
    {
      Weight current = block( i, j );

      switch( current )
      {
        case Full : totalWeight  += 1; break;
        case Strong : totalWeight  += FACTOR_AREA_STRONG; break;
        case Weak : totalWeight  += FACTOR_AREA_WEAK; break;
        case Empty : break;
      }
    }
  unsigned long factor2 = (factor * (long) factor);
    // factor2: number of cells of the smaller size that fits
    // in a cell of the larger size

  double weight = double(totalWeight / factor2 * 100 );
  // Sets the weight of the group of cells according to the individual weight
  // of each cell (rounding the value)

  if ( weight == 0.0  ) return Signature4CRS::Empty;  // weight = 0
  if ( weight == 100.0  ) return Signature4CRS::Full;  // weight = 100
  if ( weight >  50.0 ) return Signature4CRS::Strong;  // weight (50,100)
  // if ( weight >  0  ) 
  return Signature4CRS::Weak;  // weight (0, 50)

}

Signature4CRS::Weight Signature4CRS::block( long minX, long minY, 
         unsigned long sizeOfBlock ) const
{

  Coordinate min=map->mbr.min;

  min.x = min.x & (0xFFFFFFFFlu << map->potency);
  min.y = min.y & (0xFFFFFFFFlu << map->potency);
  minX  = minX  & (0xFFFFFFFFlu << map->potency);
  minY  = minY  & (0xFFFFFFFFlu << map->potency);

  int x = (int) ((minX - min.x) / this->sizeOfBlock),
      y = (int) ((minY - min.y) / this->sizeOfBlock);

  if( (unsigned long)this->sizeOfBlock == sizeOfBlock )
  {
	  return block( x, y );
  }
  else
    if( (unsigned long)this->sizeOfBlock < sizeOfBlock )
    {
      unsigned temWeak = 0;
      unsigned long fullCells = 0;

#ifdef APPROXIMATE_AREA
      return resolutionChange( x,  y, sizeOfBlock);
#endif

      int factor = (unsigned) (sizeOfBlock/this->sizeOfBlock),
          startX = x < 0 ? 0 : x,
          startY = y < 0 ? 0 : y,
          endX = x + factor > (int) map->dx ? map->dx : x + factor,
          endY = y + factor > (int) map->dy ? map->dy : y + factor,
          i, j;

      for( i = startX; i < endX; i++ )
        for( j = startY; j < endY; j++ )
        {
          Weight current = block( i, j );

          switch( current )
          {
             case Full : fullCells  += 2; break;
             case Strong : fullCells  += 1; break;
             case Weak : temWeak = 1; break;
             case Empty : break;

          }
        }

      unsigned long factor2 = (factor * (long) factor);
      // factor2: number of cells of the smaller size that fit in a cell 
      // with larger size

      if( fullCells == 2 * factor2 )
        return Full;
        //if the "weight" of full cells equals the number of total cells
        //than returns full (100% of weight)
      else
        if( fullCells > factor2 )
          return Strong;
          //if the "weight" of full cells is larger than half of the total 
          // number of cells then returns Strong ]50%,100%[ of weight
        else
          if( fullCells < factor2 )
            return (temWeak || fullCells > 0 ) ? Weak : Empty;
            //if the "weight" of full cells is smaller than half of the
            // total number of cells and exists weak or strong or full
            // than returns wead ]0%,50%] of weight else, returns empty
          else
            return temWeak ? Strong : Weak;
            //if the "weight" of full cells equals half the number
            //of total cells and there is no weak cell, then returns strong
            //else returns weak

    }
    else
    {
      //cout << "Critical error in " __FILE__ << ", line " <<  __LINE__ << endl;
      abort();

      return Empty;
    }
}

int existsIntersection( const Signature4CRS* a, const Signature4CRS* b )
{
  unsigned long sizeOfBlock = MAX( a->sizeOfBlock, b->sizeOfBlock );
  unsigned potency = MAX( a->map->potency, b->map->potency );
  Coordinate min( MAX( a->map->mbr.min.x, b->map->mbr.min.x ),
                  MAX( a->map->mbr.min.y, b->map->mbr.min.y ) ),
             max( MIN( a->map->mbr.max.x, b->map->mbr.max.x ),
                  MIN( a->map->mbr.max.y, b->map->mbr.max.y ) );
  long i, j, maybe = 0;

  (a->sizeOfBlock == b->sizeOfBlock ?
   sameScales :
   differentScales)++;

  min.x = min.x & (0xFFFFFFFFlu << potency);
  min.y = min.y & (0xFFFFFFFFlu << potency);
  max.x = max.x & (0xFFFFFFFFlu << potency);
  max.y = max.y & (0xFFFFFFFFlu << potency);

  for( i = min.x; i <= max.x; i += sizeOfBlock )
    for( j = min.y; j <= max.y; j += sizeOfBlock )
    {
      Signature4CRS::Weight blockA = a->block( i, j, sizeOfBlock ),
                           blockB = b->block( i, j, sizeOfBlock );

      if( blockA == Signature4CRS::Empty || blockB == Signature4CRS::Empty )
        continue; // Does not have intersection
      else if( (blockA == Signature4CRS::Full 
                         || blockB == Signature4CRS::Full) ||
               (blockA == Signature4CRS::Strong 
                         && blockB == Signature4CRS::Strong) )
        return 2;
      else
        maybe = 1;
    }

  return maybe;
}

void Signature4CRS::RasterMap4CRS::block(unsigned x, unsigned y, Weight weight)
{
  if( x < header.dx && y < header.dy && weight != Empty )
  {
    unsigned index = x*header.dy + y,
             position = index / (8 * sizeof( GroupOfBits )),
             displacement = 8 * sizeof( GroupOfBits ) - 1 
             - (index % (8 * sizeof( GroupOfBits )));

    bits0[ position ] |= ((weight & 0x1lu) >> 0) << displacement;
    bits1[ position ] |= ((weight & 0x2lu) >> 1) << displacement;
  }
}

Signature4CRS& Signature4CRS::operator=(const Signature4CRS& a)
{
  this->attr_map = a.fullMap();
  return *this;
}

int Signature4CRS::operator == ( const Signature4CRS& a ) const
{
  return !memcmp( &attr_map, &a.attr_map, sizeof attr_map );
}

long double Signature4CRS::approximateArea()
{
	double nCellType[4]={0, 0, 0, 0};
	long cellSize = 1l << map->potency;
	MBR alignedMBR = BBox2D::alignedMBR(map->mbr, cellSize);
	return approximateArea(nCellType, alignedMBR);
}

long double Signature4CRS::approximateArea(double &deltaConfidence)
{
	//cout << "Entrou em area1..." << endl; // verificar aqui
	double nCellType[4]={0, 0, 0, 0};
	long cellSize = 1l << map->potency;
	MBR alignedMBR = BBox2D::alignedMBR(map->mbr, cellSize);
	double area = approximateArea(nCellType, alignedMBR, deltaConfidence);

	double resultMin = area - deltaConfidence;
	double resultMax = area + deltaConfidence;

	ofstream myfile;
	myfile.open ("C:/resultados/result2.txt", ios::app);
	myfile << ", " << area << ", " << resultMin << ", " << resultMax;
	double ncti = 0;
	for (int i=0; i<4; i++)
	{
		ncti = nCellType[i];
		myfile << ", " << ncti;
	}
	myfile << ", ";
	myfile.close();

	return area;
}

long double Signature4CRS::approximateArea(double nCellType[4], MBR alignedMBR, double &deltaConfidence)
{
	//cout << "Entrou em area2..." << endl;
	long blockArea = sizeOfBlock * sizeOfBlock;
	double area = approximateArea(nCellType, alignedMBR);
	if ((nCellType[1] != 0) && (nCellType[2] != 0))
		deltaConfidence = ( nCellType[1] * CONFIDENCE_INTERVAL * sqrt(VARIANCE/nCellType[1]) +
				   nCellType[2] * CONFIDENCE_INTERVAL * sqrt(VARIANCE/nCellType[2]) ) * blockArea;
	return area;
}

long double Signature4CRS::approximateArea(double nCellType[4], MBR alignedMBR)
{
	//cout << "Entrou em area3..." << endl;
	long i = 0, j = 0;
	long blockArea = sizeOfBlock * sizeOfBlock;

	for( i = alignedMBR.min.x; i < alignedMBR.max.x; i += sizeOfBlock )
	{
		for( j = alignedMBR.min.y; j < alignedMBR.max.y; j += sizeOfBlock )
		{
			Signature4CRS::Weight weight = block(i, j, sizeOfBlock);
			nCellType[weight]++;
		}
	}

	return ( (	nCellType[Signature4CRS::Full] +
				nCellType[Signature4CRS::Strong] * FACTOR_AREA_STRONG +
				nCellType[Signature4CRS::Weak] * FACTOR_AREA_WEAK  ) * blockArea );
}

double Signature4CRS::approximateOverlappingArea(const Signature4CRS* signat4CRS2)
{
	double nOccupation[4][4] = 
			{ { 0, 0, 0, 0 },
			  { 0, 0, 0, 0 },
			  { 0, 0, 0, 0 },
			  { 0, 0, 0, 0 } };
	return approximateOverlappingArea(signat4CRS2, nOccupation );
}

double Signature4CRS::approximateOverlappingArea(const Signature4CRS* signat4CRS2, double &deltaConfidence)
{
	long blockArea = sizeOfBlock * sizeOfBlock;
	double nOccupation[4][4] = 
			{ { 0, 0, 0, 0 },
			  { 0, 0, 0, 0 },
			  { 0, 0, 0, 0 },
			  { 0, 0, 0, 0 } };

	double area = approximateOverlappingArea(signat4CRS2, nOccupation);

	double variance;
	deltaConfidence=0;
	for (int i=0; i<4; i++){
		for (int j=0; j<4; j++){
			if(nOccupation[i][j] == 0) 
				continue;
			if((i==1) && (j==1)) 
				variance = VARIANCE_PxP;
			else if(((i==1) && (j==2)) || ((i==2) && (j==1))) 
				variance = VARIANCE_PxM;
			else if(((i==1) && (j==3)) || ((i==3) && (j==1))) 
				variance = VARIANCE_PxC;
			else if((i==2) && (j==2)) 
				variance = VARIANCE_MxM;
			else 
				continue;
			//cout << "nCellType[" << i << "]" << "[" << j << "] = " << nOccupation[i][j] << endl;
			deltaConfidence += (nOccupation[i][j] * CONFIDENCE_INTERVAL * sqrt(variance / nOccupation[i][j]));
		}
	}

	deltaConfidence *= blockArea;

	double areaMin = area - deltaConfidence;
	double areaMax = area + deltaConfidence;

	ofstream myfile;
	myfile.open ("C:/resultados/result2.txt", ios::app);
	myfile << area << ", " << areaMin << ", " << areaMax;
	double nctij = 0;
	int nOccupationT = 0;
	for (int i=0; i<4; i++){
		for (int j=0; j<4; j++){
			nctij = nOccupation[i][j];
			nOccupationT += nOccupation[i][j];
			myfile << ", " << nctij;
		}
	}
	myfile.close();

	return area;
}

double Signature4CRS::approximateOverlappingArea(const Signature4CRS* signat4CRS2, double nOccupation[4][4] )
{
	if ( existsIntersection(this->map->mbr, signat4CRS2->map->mbr) )
	{
		double blockArea;
		
		Coordinate min( MAX( this->map->mbr.min.x, signat4CRS2->map->mbr.min.x ), MAX( this->map->mbr.min.y, signat4CRS2->map->mbr.min.y ) );
		Coordinate max( MIN( this->map->mbr.max.x, signat4CRS2->map->mbr.max.x ), MIN( this->map->mbr.max.y, signat4CRS2->map->mbr.max.y ) );
		
		if (this->IsSmallerThan(signat4CRS2))
		{
			MBR interMBR(min, max);
			MBR alignedMBR = BBox2D::alignedMBR(interMBR, signat4CRS2->sizeOfBlock);

			return approximateOverlappingArea(this, signat4CRS2, alignedMBR, blockArea, nOccupation);
		}
		else
		{
			MBR interMBR(min, max);
			MBR alignedMBR = BBox2D::alignedMBR(interMBR, signat4CRS2->sizeOfBlock);

			return approximateOverlappingArea(signat4CRS2, this, alignedMBR, blockArea, nOccupation);	
		}
	}
	return 0;
}


double Signature4CRS::approximateOverlappingArea(const Signature4CRS* smallerSignature, const Signature4CRS* largestSignature,
												MBR interMBR, double &blockArea, double nOccupation[4][4])
{
	// Matrix: Empty, Weak, Strong and Full
	double occupation[4][4] =
	{ { 0, 0, 0, 0 },
	  { 0, 0.0406, 0.1492, 0.1887 },
      { 0, 0.1492, 0.6578, 0.8063 },
      { 0, 0.1887, 0.8063, 1 } };
	
	double approximateArea = 0;

	for( long i = interMBR.min.x; i < interMBR.max.x; i += largestSignature->sizeOfBlock)
	{
		for( long j = interMBR.min.y; j < interMBR.max.y; j += largestSignature->sizeOfBlock)
		{
			Signature4CRS::Weight quadraA = smallerSignature->block(i, j, largestSignature->sizeOfBlock);
			//cout << "quadraA = " << quadraA << endl;
			Signature4CRS::Weight quadraB = largestSignature->block(i, j, largestSignature->sizeOfBlock);            
			//cout << "quadraB = " << quadraB << endl;
			approximateArea += occupation[quadraA][quadraB];
			nOccupation[quadraA][quadraB] = nOccupation[quadraA][quadraB] + 1;
		}
	}

	blockArea = largestSignature->sizeOfBlock * largestSignature->sizeOfBlock;

	return approximateArea * blockArea;
}

double Signature4CRS::similar(Signature4CRS* signat4CRS2, double &resultMin, double &resultMax)
{
	ofstream myfile2;
	myfile2.open ("C:/resultados/sizeofblock.txt", ios::app);
	myfile2 << this->sizeOfBlock << "," << signat4CRS2->sizeOfBlock << endl;
	myfile2.close();

	double deltaConfidenceI;
	double intersectionArea = this->approximateOverlappingArea(signat4CRS2, deltaConfidenceI);
	
	if(!intersectionArea) return 0;
	
	double deltaConfidenceU;

	Signature4CRS* signat4CRSPlus = this->plus(signat4CRS2);

	ofstream myfile;
	myfile.open ("C:/resultados/result2.txt", ios::app);
	
	if (signat4CRSPlus == NULL)
	{
		myfile << "\n";
		myfile.close();
		return 0;
	}
	//cout << "Passou por plus = " << endl;

	double unionArea = signat4CRSPlus->approximateArea(deltaConfidenceU);

	//cout << "unionArea = " << unionArea << endl;
	//cout << "intersectionArea = " << intersectionArea << endl;
	//cout << "deltaConfidenceI = " << deltaConfidenceI << endl;
	//cout << "deltaConfidenceU = " << deltaConfidenceU << endl;

	resultMin = (intersectionArea - deltaConfidenceI) / (unionArea + deltaConfidenceU);
	resultMax = (intersectionArea + deltaConfidenceI) / (unionArea - deltaConfidenceU);

	//cout << "resultMin = " << resultMin << endl;
	//cout << "resultMax = " << resultMax << endl;

	if (unionArea == 0) return 0;

	double similarResult = intersectionArea / unionArea;
	
	myfile << similarResult << ", " << resultMin << ", " << resultMax << "\n";
	myfile.close();

	return similarResult;
}
double Signature4CRS::similar(Signature4CRS* signat4CRS2)
{
	double intersectionArea = this->approximateOverlappingArea(signat4CRS2);
	
	if(!intersectionArea)
		return 0;

	double unionArea = this->plus(signat4CRS2)->approximateArea();

	return intersectionArea / unionArea;
}

Signature4CRS* Signature4CRS::plus(Signature4CRS* signat4CRS2)
{
	//cout << "Entrou em plus..." << endl;
	if ( existsIntersection(this->map->mbr, signat4CRS2->map->mbr) )
	{
		// Compute max and min coordinates of the union MBR
		Coordinate min( MIN( this->map->mbr.min.x, signat4CRS2->map->mbr.min.x ), MIN( this->map->mbr.min.y, signat4CRS2->map->mbr.min.y ) );
		Coordinate max( MAX( this->map->mbr.max.x, signat4CRS2->map->mbr.max.x ), MAX( this->map->mbr.max.y, signat4CRS2->map->mbr.max.y ) );
		
		if (this->IsSmallerThan(signat4CRS2))
		{
			MBR unionMBR(min, max);
			MBR alignedMBR = BBox2D::alignedMBR(unionMBR, signat4CRS2->sizeOfBlock);

			//cout << "Entrou em plusS1menorQueS2..." << endl;

			return plus(this, signat4CRS2, unionMBR, alignedMBR);
		}
		else
		{
			MBR unionMBR(min, max);
			MBR alignedMBR = BBox2D::alignedMBR(unionMBR, this->sizeOfBlock);

			//cout << "Entrou em plusS1maiorQueS2..." << endl;

			return plus(signat4CRS2, this, unionMBR, alignedMBR);
		}
	}

	return this; // It'll change

	// Add faces

	//return new Signature4CRS();
}

Signature4CRS* Signature4CRS::plus( const Signature4CRS* smallerSignature, 
								    const Signature4CRS* largestSignature, MBR unionMBR, MBR alignedMBR )
{
	//cout << "Entrou em plusEspecifico..." << endl;
	long dx, dy;

	dx = (alignedMBR.max.x - alignedMBR.min.x)/largestSignature->sizeOfBlock;
	dy = (alignedMBR.max.y - alignedMBR.min.y)/largestSignature->sizeOfBlock;

	long numCells = dx * dy;

	//cout << "NumCells = " << numCells << endl;

	if (numCells > 500) return NULL;

	RasterMap4CRS rasterMap4CRS(1, unionMBR, dx, dy, largestSignature->map->potency);

	rasterMap4CRS.setGroupOfBits(Signature4CRS::Empty);

	MBR alignedMBRlargestSignat = BBox2D::alignedMBR(largestSignature->map->mbr, largestSignature->sizeOfBlock);

	//This variables are used to compute the cell's (x, y) coordinates of union signature considering the resolution change of largest signature.
	long correcti, correctj;

	// This variables are used to compute the displacement between the cell's position in the original sinature and the union signature
	long shiftX, shiftY;

	shiftX = (alignedMBRlargestSignat.min.x - alignedMBR.min.x);
	shiftY = (alignedMBRlargestSignat.min.y - alignedMBR.min.y);

	Signature4CRS::Weight weightL;

	//cout << "Entrou em plus Inicio 1o for..." << endl;

	for( long i = alignedMBRlargestSignat.min.x; i < alignedMBRlargestSignat.max.x; i += largestSignature->sizeOfBlock)
	{
		for( long j = alignedMBRlargestSignat.min.y; j < alignedMBRlargestSignat.max.y; j += largestSignature->sizeOfBlock)
		{
			correcti = ( (i - alignedMBRlargestSignat.min.x) + shiftX ) / largestSignature->sizeOfBlock;
			correctj = ( (j - alignedMBRlargestSignat.min.y) + shiftY ) / largestSignature->sizeOfBlock;
			weightL = largestSignature->block(i, j, largestSignature->sizeOfBlock);
			rasterMap4CRS.block(correcti, correctj, weightL);
		}
	}

	//cout << "Entrou em plus Inicio 2o for..." << endl;

	MBR alignedMBRsmallerSignat = BBox2D::alignedMBR(smallerSignature->map->mbr, largestSignature->sizeOfBlock);

	shiftX = (alignedMBRsmallerSignat.min.x - alignedMBR.min.x);
	shiftY = (alignedMBRsmallerSignat.min.y - alignedMBR.min.y);

	Signature4CRS::Weight weightU, weightS;

	for( long i = alignedMBRsmallerSignat.min.x; i < alignedMBRsmallerSignat.max.x; i += largestSignature->sizeOfBlock)
	{
		for( long j = alignedMBRsmallerSignat.min.y; j < alignedMBRsmallerSignat.max.y; j += largestSignature->sizeOfBlock)
		{
			correcti = ( (i - alignedMBRsmallerSignat.min.x) + shiftX ) / largestSignature->sizeOfBlock;
			correctj = ( (j - alignedMBRsmallerSignat.min.y) + shiftY ) / largestSignature->sizeOfBlock;
			weightU = rasterMap4CRS.block(correcti, correctj);
			weightS = smallerSignature->block(i, j, largestSignature->sizeOfBlock);
			if ( (weightU ==  Signature4CRS::Empty) || (weightS == Signature4CRS::Full) )
				rasterMap4CRS.block(correcti, correctj, weightS);
			else if ( weightU ==  Signature4CRS::Weak && weightS == Signature4CRS::Strong )
				rasterMap4CRS.block(correcti, correctj, weightS);
		}
	}

	//cout << "Entrou em plus Fim 2o for..." << endl;

	Signature4CRS* unionSignature4CRS = new Signature4CRS(rasterMap4CRS);

	//cout << "Entrou em plus depois da criacao..." << endl;
	
	return unionSignature4CRS;
}

Signature4CRS* Signature4CRS::intersection(Signature4CRS* signat4CRS2)
{
	if ( existsIntersection(this->map->mbr, signat4CRS2->map->mbr) )
	{
		Coordinate min( MAX( this->map->mbr.min.x, signat4CRS2->map->mbr.min.x ), MAX( this->map->mbr.min.y, signat4CRS2->map->mbr.min.y ) );
		Coordinate max( MIN( this->map->mbr.max.x, signat4CRS2->map->mbr.max.x ), MIN( this->map->mbr.max.y, signat4CRS2->map->mbr.max.y ) );
		
		if (this->IsSmallerThan(signat4CRS2))
		{   //signat4CRS2 is greater than this
			MBR interMBR(min, max);
			MBR alignedMBR = BBox2D::alignedMBR(interMBR, signat4CRS2->sizeOfBlock);

			return intersection(this, signat4CRS2, interMBR, alignedMBR);
		}
		else
		{
			MBR interMBR(min, max);
			MBR alignedMBR = BBox2D::alignedMBR(interMBR, this->sizeOfBlock);

			return intersection(signat4CRS2, this, interMBR, alignedMBR);
		}
	}

	return NULL;
}

Signature4CRS* Signature4CRS::intersection( const Signature4CRS* smallerSignature, 
											const Signature4CRS* largestSignature, MBR interMBR, MBR alignedMBR )
{
	long dx, dy;

	dx = (alignedMBR.max.x - alignedMBR.min.x)/largestSignature->sizeOfBlock;
	dy = (alignedMBR.max.y - alignedMBR.min.y)/largestSignature->sizeOfBlock;

	RasterMap4CRS rasterMap4CRS(1, interMBR, dx, dy, largestSignature->map->potency);

	rasterMap4CRS.setGroupOfBits(Signature4CRS::Empty);

	MBR alignedMBRlargestSignat = BBox2D::alignedMBR(largestSignature->map->mbr, largestSignature->sizeOfBlock);
	MBR alignedMBRsmallerSignat = BBox2D::alignedMBR(smallerSignature->map->mbr, largestSignature->sizeOfBlock);

	long correcti, correctj;
	for( long i = alignedMBR.min.x; i < alignedMBR.max.x; i += largestSignature->sizeOfBlock)
	{
		for( long j = alignedMBR.min.y; j < alignedMBR.max.y; j += largestSignature->sizeOfBlock)
		{
			correcti = (i - alignedMBR.min.x) / largestSignature->sizeOfBlock;
			correctj = (j - alignedMBR.min.y) / largestSignature->sizeOfBlock;
			Signature4CRS::Weight weightS = smallerSignature->block(i, j, largestSignature->sizeOfBlock);
			Signature4CRS::Weight weightL = largestSignature->block(i, j, largestSignature->sizeOfBlock);

			if (weightL == Signature4CRS::Full)
				rasterMap4CRS.block(correcti, correctj, weightS);
			else if (weightS == Signature4CRS::Full)
				rasterMap4CRS.block(correcti, correctj, weightL);
			else if ( (weightL == Signature4CRS::Empty) || (weightS == Signature4CRS::Empty) )
				rasterMap4CRS.block(correcti, correctj, Signature4CRS::Empty);
			else if ( (weightL == Signature4CRS::Strong) && (weightS == Signature4CRS::Strong) )
				rasterMap4CRS.block(correcti, correctj, Signature4CRS::Strong);
			else	/* ( (b.type == Strong) and (s.type==Weak) ) or ( (s.type == Strong) and (b.type==Weak) ) or  ( (b.type == Weak) and (s.type==Weak) ) */
				rasterMap4CRS.block(correcti, correctj, Signature4CRS::Weak);
		}
	}

	Signature4CRS* unionSignature4CRS = new Signature4CRS(rasterMap4CRS);
	
	return unionSignature4CRS;
}

bool Signature4CRS::IsSmallerThan(const Signature4CRS* signat4CRS2)
{
	return (this->map->potency < signat4CRS2->map->potency);
}

//------------------------------------------------------------------------------------

